package com.jzo2o.common.utils;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 切面工具类，提供AOP相关的方法获取和表达式解析功能
 */
public class AspectUtils {

    /**
     * 获取被拦截的方法对象
     * 注意：MethodSignature.getMethod() 获取的是顶层接口或者父类的方法对象
     * 如需当前对象的实际方法，需使用反射进一步获取
     *
     * @param pjp 连接点对象
     * @return 被拦截的方法对象
     * @throws IllegalArgumentException 当连接点不是方法时抛出
     */
    public static Method getMethod(ProceedingJoinPoint pjp) {
        //获取参数的类型
        Signature sig = pjp.getSignature();
        if (sig instanceof MethodSignature) {
            MethodSignature methodSignature = (MethodSignature) sig;
            return methodSignature.getMethod();
        } else {
            throw new IllegalArgumentException("It's not method");
        }
    }

    /**
     * 在AOP切面中使用SPEL表达式对模板字符串进行格式化，替换为实际参数值
     *
     * @param formatter 包含SPEL表达式的模板字符串
     * @param method    被拦截的方法对象
     * @param args      方法参数值数组
     * @return 格式化后的字符串；模板为空或无表达式时返回原模板
     */
    public static String parse(String formatter, Method method, Object[] args) {
        if(formatter == null || formatter.indexOf("{") < 0){
            return formatter;
        }
        LocalVariableTableParameterNameDiscoverer nameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
        return SpelUtils.parse(formatter, nameDiscoverer.getParameterNames(method), args);
    }

    /**
     * 在AOP切面中批量使用SPEL表达式对多个模板字符串进行格式化
     *
     * @param formatters 包含SPEL表达式的模板字符串数组
     * @param method     被拦截的方法对象
     * @param args       方法参数值数组
     * @return 格式化后的字符串列表；模板数组为空时返回null
     */
    public static List<Object> parseList(String[] formatters, Method method, Object[] args) {
        if (ArrayUtils.isEmpty(formatters)) {
            return null;
        }
        return Arrays.stream(formatters)
                .map(formatter -> AspectUtils.parse(formatter, method, args))
                .collect(Collectors.toList());
    }
}
